﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Drifting.Foundation;

namespace Drifting.Graphics.EffectObjects
{
    public class Line : EffectObject
    {
        static short[] quad_Indices;
        private VertexPositionColor[] vertices;
        private BasicEffect effects;
        private Matrix configuration;

        public Line(float width, Color color, GraphicsDevice device)
            : base(device)
        {
            vertices = new VertexPositionColor[6];

            Vector3 v0 = new Vector3(1f, 0, 0);
            Vector3 v1 = new Vector3(0, 0, -width);
            Vector3 v2 = new Vector3(0, 0, width);
            Vector3 v3 = new Vector3(0.000001f, 0, 0);
            Vector3 v4 = new Vector3(1f, width, 0);
            Vector3 v5 = new Vector3(1f, -width, 0);
            
            vertices[0] = new VertexPositionColor(v0, color);
            vertices[1] = new VertexPositionColor(v1, color);
            vertices[2] = new VertexPositionColor(v2, color);
            vertices[3] = new VertexPositionColor(v3, color);
            vertices[4] = new VertexPositionColor(v4, color);
            vertices[5] = new VertexPositionColor(v5, color);

            if (quad_Indices == null)
            {
                quad_Indices = new short[] { 0, 1, 2, 
                                             3, 4, 5};
                
            }
            effects = new BasicEffect(device);

            configuration = Matrix.Identity;
        }

        public void Draw(Matrix view, Matrix projection, float[] f1, float[] f2)
        {
            float d1 = f2[0] - f1[0];
            float d2 = f2[1] - f1[1];
            float d3 = f2[2] - f1[2];
            Vector3 v_delta = new Vector3(d1, d2, d3);
            Vector3 v_position = new Vector3(f1[0], f1[1], f1[2]);
            Draw(view, projection, v_position, v_delta);
        }

        public void Draw(Matrix view, Matrix projection, float[] f33)
        {
            float d1 = f33[3] - f33[0];
            float d2 = f33[4] - f33[1];
            float d3 = f33[5] - f33[2];
            Vector3 v_delta = new Vector3(d1, d2, d3);
            Vector3 v_position = new Vector3(f33[0], f33[1], f33[2]);
            Draw(view, projection, v_position, v_delta);
        }

        /// <summary>
        /// edges will be drawn if the length is less or equals to length_limit
        /// </summary>
        /// <param name="view"></param>
        /// <param name="projection"></param>
        /// <param name="f33"></param>
        /// <param name="length_limit"></param>
        public void Draw(Matrix view, Matrix projection, float[] f33, float length_limit)
        {
            float d1 = f33[3] - f33[0];
            float d2 = f33[4] - f33[1];
            float d3 = f33[5] - f33[2];

            double length2 = d1 * d1 + d2 * d2 + d3 * d3;
            if (length2 <= length_limit * length_limit)
            {
                Vector3 v_delta = new Vector3(d1, d2, d3);
                Vector3 v_position = new Vector3(f33[0], f33[1], f33[2]);
                Draw(view, projection, v_position, v_delta);
            }
        }

        public void Draw(Matrix view, Matrix projection, Vector3 v_position, Vector3 v_delta)
        {
            Vector3 v_original = new Vector3(1, 0, 0);
            float v_delta_length = v_delta.Length();

            Vector3 axis = MathAssistant.vector_cross3(v_original, v_delta);
            float sinT = axis.Length() / v_delta_length;
            axis.Normalize();
            float cosT = (float)MathAssistant.vector_dotProduct(v_original, v_delta) / v_delta_length;
            float T = MathAssistant.AngleFromSinCos(sinT, cosT);

            Matrix config = Matrix.CreateScale(v_delta_length, 1, 1) * Matrix.CreateFromAxisAngle(axis, T) * Matrix.CreateTranslation(v_position);

            effects.World = config;
            effects.VertexColorEnabled = true;
            effects.View = view;
            effects.Projection = projection;

            effects.CurrentTechnique.Passes[0].Apply();
            device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, 6, quad_Indices, 0, 2);
        }

        override public void Draw(Matrix view, Matrix projection)
        {
            effects.VertexColorEnabled = true;
            effects.World = configuration;
            effects.View = view;
            effects.Projection = projection;

            effects.CurrentTechnique.Passes[0].Apply();
            device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, 6, quad_Indices, 0, 2);

            throw new NotSupportedException("Call the overloaded Draw function instead");
        }
    }
}
